﻿// Copyright (c) 2012 - 2020 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2018-12-05 version 3.1.5 Jared Zheng <jaredz at outlook dot com>

#ifndef __AUTHORDB_SERVER_IMP_H__
#define __AUTHORDB_SERVER_IMP_H__

#pragma once

#include "commonpacket.h"
#include "CommonServer.h"
#include "CommonRoutine.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 授权数据服务器实现
class CAuthorDBServer : public ICommonServer, public CPAKHandler
{
public:
    CAuthorDBServer(void);
    virtual ~CAuthorDBServer(void);
    // CComponent
    // Command to set param value
    virtual UInt   Command(PCXStr pszCMD, uintptr_t utParam) OVERRIDE;
    virtual UInt   Update(void) OVERRIDE;

    virtual UInt   Init(CEventHandler& EventHandlerRef, CServerConfig& ConfigRef) OVERRIDE;
    virtual void   Exit(void) OVERRIDE;

    virtual bool   Start(void) OVERRIDE;
    virtual bool   Pause(bool bPause = true) OVERRIDE;
    virtual void   Stop(void) OVERRIDE;
    // CPAKHandler
    virtual bool   OnTcpDispatch(const PacketPtr& PktPtr, PTCP_PARAM pTcp) OVERRIDE;
    virtual bool   OnUdpDispatch(const PacketPtr& PktPtr, PUDP_PARAM pUdp) OVERRIDE;//
    virtual bool   OnTcpAccept(Socket sAccept, Socket sListen) OVERRIDE;
    virtual bool   OnTcpConnect(UInt uError, Socket sConnect) OVERRIDE;
    virtual bool   OnTcpRecv(size_t stSize, PTCP_PARAM pTcp) OVERRIDE;//
    virtual bool   OnTcpSend(UInt uQueueLimit, Socket sSocket) OVERRIDE;//
    virtual bool   OnTcpClose(Socket sSocket, ULLong ullLiveData) OVERRIDE;

    virtual bool   OnUdpRecv(size_t stSize, PUDP_PARAM pUdp) OVERRIDE;//
    virtual bool   OnUdpSend(UInt uQueueLimit, Socket sSocket) OVERRIDE;//
    virtual bool   OnUdpClose(Socket sSocket, ULLong ullLiveData) OVERRIDE;//
    // Routine
    virtual Socket_t          GetSocket(UInt uType) OVERRIDE;
    virtual PSERVER_INFO      GetServerInfo(UInt uType) OVERRIDE;
    virtual PSVR_COMMON_MAP   GetServerMap(UInt uType) OVERRIDE;
    virtual PRESULT_CHAIN     GetServerSort(UInt uType) OVERRIDE;
    virtual CServerConfig&    GetConfig(void) OVERRIDE;
    virtual CFileLog&         GetFileLog(void) OVERRIDE;
    virtual CEventHandlerPtr& GetMgrHandler(void) OVERRIDE;
    virtual CNetworkPtr&      GetNetworkPtr(void) OVERRIDE;
private:
    CAuthorDBServer(const CAuthorDBServer&);
    CAuthorDBServer& operator=(const CAuthorDBServer&);
    /// 配置相关
    bool  LoadConfig(void);
    void  UnloadConfig(void);

    bool  StartConnectCenterServer(void);
    bool  StartListen(void);

    bool  CheckConnectCenterServer(void);
    bool  CheckListen(void);

    void  StopConnectCenterServer(void);
    void  StopListen(void);

    /// 向同步管理服务器注册/注销
    void  LinkCenterServer(void);
    void  UnlinkCenterServer(void);

    /// 处理同步管理服务器的信令包
    bool  DispatchCenterServer(const PacketPtr& PktPtr, PTCP_PARAM pTcp);
    /// 处理授权网关服务器的信令包
    bool  DispatchAuthorServer(const PacketPtr& PktPtr, PTCP_PARAM pTcp);

    /// 同步服务器信息
    bool  SyncServerInfo(void);

    /// 网络服务器处理-注册
    bool  OnServerLink(CNETLink* pLink, Socket sSocket);
    /// 网络服务器处理-更新
    bool  OnServerUpdate(CNETUpdate* pUpdate, Socket sSocket);
    /// 网络服务器处理-注销
    bool  OnServerUnlink(CPAKHeadBase* pUnlink, Socket sSocket, SERVER_UNLINK& su);
    /// 注册服务器数据
    bool  ServerLink(CNETLink* pLink, ULLong ullKey);
    /// 更新服务器数据
    bool  ServerUpdate(CNETUpdate* pUpdate, ULLong ullKey);
    /// 注销服务器数据
    bool  ServerUnlink(Socket sSocket, SERVER_UNLINK& su);

    bool  LoadExtConfig(void);
    bool  LoadExtRoutine(CKVNode& Root);
    bool  CreateRTTIObject(PCXStr pszObject, PCXStr pszName, PCXStr pszModule);
    bool  UnloadExtConfig(void);
    bool  UnloadExtRoutine(void);
private:
    Int                 m_nStatus;         ///< 服务器状态
    Int                 m_nCenterLink;     ///< 连接同步管理服务器状态
    // 框架例程开关, 由框架例程通过调用Command修改服务器实例对应参数
    Int                 m_nServerInfo;     ///< 例程需要处理服务器同步信息PAKE_LINK/PAKE_UPDATE/PAKE_UNLINK的SERVER_INFO
    Int                 m_nServerAck;      ///< 例程需要处理连接上服务器ACK信息PAKE_LINKACK/PAKE_UNLINKACK
    Int                 m_nSyncInfo;       ///< 例程需要处理服务器PAKE_LINK/PAKE_UPDATE同步信息时增加其他数据
    Int                 m_nCommonEvent;    ///< 例程需要处理服务器内部通用PAKE_COMMON_BEGIN/PAKE_COMMON_END事件
    //
    CServerConfig*      m_pConfig;         ///< 配置
    Socket              m_sConnectCenter;  ///< 内网, 连接同步管理服务器
    Socket              m_sListenInternal; ///< 内网, 监听授权网关服务器
    CFileLog            m_FileLog;         ///< 简单文本日志
    CEventHandlerPtr    m_MgrHandler;      ///< 控制台回调接口
    CNetworkPtr         m_NetworkPtr;      ///< 网络
    CCommonRoutinePtr   m_RoutinePtr;      ///< 例程处理
    COMMON_ADDR         m_ServerInfo;      ///< 本服务器信息
    SERVER_INFO         m_AuthorInfo;      ///< 授权网关服务器组统计数据
    SVR_AUTHOR_MAP      m_Author;          ///< 授权网关服务器信息
};

INLINE CAuthorDBServer::CAuthorDBServer(void)
: m_nStatus(STATUSS_NONE)
, m_nCenterLink(STATUSL_NONE)
, m_nServerInfo(TRUE)
, m_nServerAck(FALSE)
, m_nSyncInfo(FALSE)
, m_nCommonEvent(FALSE)
, m_pConfig(nullptr)
, m_sConnectCenter(0)
, m_sListenInternal(0)
, m_FileLog(false)
{
}

INLINE CAuthorDBServer::~CAuthorDBServer(void)
{
}

INLINE CAuthorDBServer::CAuthorDBServer(const CAuthorDBServer&)
: m_nStatus(STATUSS_NONE)
, m_nCenterLink(STATUSL_NONE)
, m_nServerInfo(TRUE)
, m_nServerAck(FALSE)
, m_nSyncInfo(FALSE)
, m_nCommonEvent(FALSE)
, m_pConfig(nullptr)
, m_sConnectCenter(0)
, m_sListenInternal(0)
, m_FileLog(false)
{
}

INLINE CAuthorDBServer& CAuthorDBServer::operator=(const CAuthorDBServer&)
{
    return (*this);
}

INLINE bool CAuthorDBServer::OnUdpDispatch(const PacketPtr&, PUDP_PARAM)
{
    // 1. PUDP_PARAM->pCache != nullptr时上层可以保存网络层申请的缓存数据
    //    PUDP_PARAM->pCache, PUDP_PARAM->index是网络层申请的缓存数据的起始地址和索引号
    // 2. PUDP_PARAM->pData为当前数据开始地址, PUDP_PARAM->stSize为当前数据大小
    // 3. 如果上层保存缓存, 设置PUDP_PARAM->pData为nullptr通知网络层不要再使用当前缓存
    // 4. 释放缓存使用MObject::sMCFree(index, pCache)
    return false;
}

INLINE bool CAuthorDBServer::OnTcpRecv(size_t, PTCP_PARAM)
{
    return false;
}

INLINE bool CAuthorDBServer::OnTcpSend(UInt, Socket)
{
    return true;
}

INLINE bool CAuthorDBServer::OnUdpRecv(size_t, PUDP_PARAM)
{
    return false;
}

INLINE bool CAuthorDBServer::OnUdpSend(UInt, Socket)
{
    return true;
}

INLINE bool CAuthorDBServer::OnUdpClose(Socket, ULLong)
{
    return false;
}

INLINE Socket_t CAuthorDBServer::GetSocket(UInt)
{
    return 0;
}

INLINE PSERVER_INFO CAuthorDBServer::GetServerInfo(UInt uType)
{
    if (uType == PAKT_AUTHOR)
    {
        return &m_AuthorInfo;
    }
    return &m_ServerInfo;
}

INLINE PSVR_COMMON_MAP CAuthorDBServer::GetServerMap(UInt uType)
{
    if (uType == PAKT_AUTHOR)
    {
        return (PSVR_COMMON_MAP)&m_Author;
    }
    return nullptr;
}

INLINE PRESULT_CHAIN CAuthorDBServer::GetServerSort(UInt)
{
    return nullptr;
}

INLINE CServerConfig& CAuthorDBServer::GetConfig(void)
{
    return (*m_pConfig);
}

INLINE CFileLog& CAuthorDBServer::GetFileLog(void)
{
    return m_FileLog;
}

INLINE CEventHandlerPtr& CAuthorDBServer::GetMgrHandler(void)
{
    return m_MgrHandler;
}

INLINE CNetworkPtr& CAuthorDBServer::GetNetworkPtr(void)
{
    return m_NetworkPtr;
}

INLINE bool CAuthorDBServer::ServerLink(CNETLink* pLink, ULLong ullKey)
{
    PINDEX index = nullptr;
    // 1.获取信息
    SVR_AUTHOR_MAP::SVR_PAIR Pair;
    Pair.ullKey = ullKey;
    Pair.Value.Copy(pLink->GetServerStatus());
    assert(Pair.Value.usStatus == STATUSU_LINK);
    assert(pLink->CheckStream());
    Pair.Value.Addr(pLink->GetStream());
    {
        CSyncLockWaitScope scope(m_Author.SvrLock);
        SVR_AUTHOR_MAP::SVR_MAP_PAIR* pPair = m_Author.SvrMap.Find(ullKey);
        if (pPair == nullptr)
        {
            index = m_Author.SvrMap.Add(ullKey, Pair.Value);
            LOGV_INFO(m_FileLog, TF("[授权数据]服务器(type=%d)%p注册1, Id=%d"), PAKT_AUTHOR, ullKey, Pair.Value.usId);
        }
        else
        {
            Pair.Value.usStatus = pPair->m_V.usStatus;
        }
    }
    if (index != nullptr)
    { 
        m_AuthorInfo.Incr(pLink->GetServerStatus());
        //m_ServerInfo.IncrOnline();
        // 2.更新控制台
        m_MgrHandler->OnHandle(PAKE_LINK, reinterpret_cast<uintptr_t>(&Pair), PAKT_AUTHOR);
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[授权数据]服务器(type=%d)%p注册时存在异常状态=%d"), PAKT_AUTHOR, ullKey, Pair.Value.usStatus);
    }
    return (index != nullptr);
}

INLINE bool CAuthorDBServer::ServerUpdate(CNETUpdate* pUpdate, ULLong ullKey)
{
    UShort usStatus = STATUSU_NONE;
    SVR_AUTHOR_MAP::SVR_PAIR Pair;
    Pair.ullKey = ullKey;
    {
        CSyncLockWaitScope scope(m_Author.SvrLock);
        SVR_AUTHOR_MAP::SVR_MAP_PAIR* pPair = m_Author.SvrMap.Find(ullKey);
        if ((pPair != nullptr) &&
            (pPair->m_V.usStatus > STATUSU_NONE) &&
            (pPair->m_V.usStatus < STATUSU_UNLINK))
        {
            Pair.Value.Copy(pPair->m_V);
            pPair->m_V.Copy(pUpdate->GetServerStatus());
        }
        else if (pPair != nullptr)
        {
            usStatus = pPair->m_V.usStatus;
        }
    }
    if (Pair.Value.usStatus > STATUSU_NONE)
    {
        m_AuthorInfo.Diff(pUpdate->GetServerStatus(), Pair.Value);
        Pair.Value.Copy(pUpdate->GetServerStatus());
        m_MgrHandler->OnHandle(PAKE_UPDATE, reinterpret_cast<uintptr_t>(&Pair), PAKT_AUTHOR);// 更新控制台
        return true;
    }
    if (usStatus != STATUSU_NONE)
    {
        LOGV_WARN(m_FileLog, TF("[授权数据]服务器(type=%d)%p更新时存在异常状态=%d"), PAKT_AUTHOR, ullKey, usStatus);
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[授权数据]服务器(type=%d)%p更新时不存在"), PAKT_AUTHOR, ullKey);
    }
    return false;
}

INLINE bool CAuthorDBServer::ServerUnlink(Socket sSocket, SERVER_UNLINK& su)
{
    // 1.更新控制台
    m_MgrHandler->OnHandle(PAKE_UNLINK, (uintptr_t)sSocket, PAKT_AUTHOR);
    SERVER_STATUS ss;
    {
        CSyncLockWaitScope scope(m_Author.SvrLock);
        SVR_AUTHOR_MAP::SVR_MAP_PAIR* pPair = m_Author.SvrMap.Find((ULLong)sSocket);
        if (pPair != nullptr)
        {
            ss  = pPair->m_V;
            LOGV_INFO(m_FileLog, TF("[授权数据]服务器(type=%d)%p注销, Id=%d"), PAKT_AUTHOR, (ULLong)sSocket, ss.usId);
            m_Author.SvrMap.RemoveAt(reinterpret_cast<PINDEX>(pPair));
        }
    }
    if (ss.usStatus > STATUSU_NONE)
    {
        m_AuthorInfo.Decr(ss);
        //m_ServerInfo.DecrOnline();

        su.tiData.usType = (UShort)PAKT_AUTHOR;
        su.tiData.usId   = ss.usId;
        return true;
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[授权数据]服务器(type=%d)%p注销时不存在"), PAKT_AUTHOR, (ULLong)sSocket);
    }
    return false;
}

#endif // __AUTHORDB_SERVER_IMP_H__
